/*
    SHA1 算法产出的是160位的摘要 即 32 * 5长度
    有五个字(这里为32位)
*/
#include <stdio.h>
#include <string.h>
 
#define EACH_HADLE_LEN 64//每次处理64字节
 
#define DWORD unsigned int
 
char cipher[40] = "\0";//32 * 5 32位表示 8个十六进制
 
typedef struct sha1_context
{
	DWORD length;
	DWORD hashRes[5];
	unsigned char block[64];//64字节的块
}sha1_context;
 
 
DWORD RoLeft(DWORD value,int index)
{
	return (value << index) ^ (value >> (32 - index));
}
 
void SHA1Init(sha1_context *sha1)
{
    if(!sha1){
        printf("%s %d the pointer is null\n",__func__,__LINE__);
    }
	sha1->length = 0;
	sha1->hashRes[0] = 0x67452301; // 初始化向量 H[0] H[1] H[2] H[3] H[4] 
	sha1->hashRes[1] = 0xefcdab89;
	sha1->hashRes[2] = 0x98badcfe;
	sha1->hashRes[3] = 0x10325476;
	sha1->hashRes[4] = 0xc3d2e1f0;
 
}

// 处理分组 
void ProcessEachBlock(sha1_context *sha1)
{
	DWORD a, b, c, d, e; //五个缓冲区
	DWORD W[80];
	DWORD temp;
	int i, j;
    if(!sha1){
        printf("%s %d the pointer is null\n",__func__,__LINE__);
    }
 
	for (i = 0, j =0; j < 16; i += 4, j++) { //初始化W[0] ~ W[15]
		/* 前64个字节，每4字节为一组，组中字节倒换顺序拼接成一个unsigned类型字，
		   类似于小端转为大端，实际存储的字节序会发生改变
		*/
		W[j] = (sha1->block[i] << 24) | (sha1->block[i + 1] << 16) |
    		(sha1->block[i + 2] << 8) | (sha1->block[i + 3]); 
	}
 
	for (i = 16; i < 80; i++) {//产生W[16] ~ W[79]
		temp = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];
		W[i] = RoLeft(temp, 1);
	}
 
	//初始化a b c d e
	a = sha1->hashRes[0];
	b = sha1->hashRes[1];
	c = sha1->hashRes[2];
	d = sha1->hashRes[3];
	e = sha1->hashRes[4];
 
	for ( i = 0; i < 20; i++){ //前20
		temp = RoLeft(a, 5) + (((c ^ d) & b) ^ d) + e + W[i] + 0x5A827999; //产生新值
		//循环赋值
		e = d;
		d = c;
		c = RoLeft(b, 30);
		b = a;
		a = temp;
	}
 
	for (i = 20; i < 40; i++){
		temp = RoLeft(a, 5) + (b ^ c ^ d) + e + W[i] + 0x6ED9EBA1;//产生新值
		//循环赋值
		e = d;
		d = c;
		c = RoLeft(b, 30);
		b = a;
		a = temp;
	}
 
	for (i = 40; i < 60; i++){
		temp = RoLeft(a, 5) + ((b & c) | (b & d) | (c & d)) + e + W[i] + 0x8F1BBCDC;//产生新值
		//循环赋值
		e = d;
		d = c;
		c = RoLeft(b, 30);
		b = a;
		a = temp;
	}
 
	for (i = 60; i < 80; i++){
		temp = RoLeft(a, 5) + (b ^ c ^ d) + e + W[i] + 0xCA62C1D6;//产生新值
		//循环赋值
		e = d;
		d = c;
		c = RoLeft(b, 30);
		b = a;
		a = temp;
	}
 
	//获得新的hash值
	sha1->hashRes[0] += a;
	sha1->hashRes[1] += b;
	sha1->hashRes[2] += c;
	sha1->hashRes[3] += d;
	sha1->hashRes[4] += e;
 
}
 
//每次处理512bit 即是处理64字节
void SHA1Update(sha1_context *sha1,char *data)
{
    int i = 0;
    if(!sha1 || !data){
        printf("%s %d the pointer is null\n",__func__,__LINE__);
    }
 
	sha1->length += strlen(data);
 
	while (sha1->length >= EACH_HADLE_LEN ){
		memcpy(sha1->block, data, EACH_HADLE_LEN);//获得M[i]
		ProcessEachBlock(sha1);
 
		data += EACH_HADLE_LEN;//移动到下一个块
		sha1->length -= EACH_HADLE_LEN;//减去相应的长度
	}
 
	// 对最后进行一轮进行一些补位操作 这里先清空 这样就可以不需要填0操作
	memset(sha1->block, 0, sizeof(char) * EACH_HADLE_LEN);
	memcpy(sha1->block, data, sha1->length);//剩余的数据进行填充
	sha1->block[sha1->length] = 0x80;//最高位填充1
	unsigned long long bitLen = sha1->length << 3;//获得bit长度 从而填充最后64bit位
	memcpy(&(sha1->block[56]), &bitLen, sizeof(unsigned long long));
	// 直接copy内存的话 因为内存是小端序的所以非常方便 学到了！
	for (i = 0; i < 4; i++) { // 这里注意要颠倒
		DWORD temp = sha1->block[56+i];
		sha1->block[56+i] = sha1->block[63 - i];
		sha1->block[63 - i] = temp;
	}
	ProcessEachBlock(sha1); // 最后一次运算 
 
}
 
void PrintSHA1(sha1_context *sha1)
{
	int i;
	char hashValue[9];
 
    if(!sha1){
        printf("%s %d the pointer is null\n",__func__,__LINE__);
    }
	printf("\nresult of the SHA - 1 is : ");
 
	for (i = 0; i < 5; i++) {
		memset(hashValue, 0, 9 * sizeof(char));
		sprintf(hashValue, "%08x", sha1->hashRes[i]); // 得到8个十六进制 
		printf("%s", hashValue);
	}
 
}
 
void SHA1Encrypt(char *data)//传入要加密的数据
{
	sha1_context sha1 = {0};
 
	SHA1Init(&sha1);//初始化长度
	SHA1Update(&sha1, data);//产生40字节的hash值
	PrintSHA1(&sha1);
}
 
int main()
{
	char data[] = "message digest";
	SHA1Encrypt(data);
}